package com.pool.db;

import com.config.Config;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author linyu.dai
 * @project rpc
 * @description 数据库连接池
 * @creat 2022/12/1 09:47:37
 */
@Slf4j
public class DBConnectionPool {

    private static Integer maxActive;

    private static Integer initialSize;

    private static Integer maxWait;

    //常驻连接个数
    private static Deque<Connection> pooledCons = new ArrayDeque<>();

    //连接数
    private static AtomicInteger connectionSize = new AtomicInteger(0);

    private static ReentrantLock lock = new ReentrantLock();

    private static Condition condition = lock.newCondition();

    static {
        maxActive = Integer.valueOf(Config.get("datasource.max-active"));
        initialSize = Integer.valueOf(Config.get("datasource.initial-size"));
        maxWait = Integer.valueOf(Config.get("datasource.max-wait"));
        initConnections();
    }

    /**
     * 初始化数据库连接
     */
    private static void initConnections(){
        for (int i = 0; i < initialSize; i++) {
            Connection connection = ConnectionFactory.createConnection();
            pooledCons.push(connection);
        }
    }

    public static Connection getConnections() throws InterruptedException {
        return getConnections(0);
    }

    /**
     * 获取数据库连接
     */
    private static Connection getConnections(int time) throws InterruptedException {
        lock.lock();
        Connection connection = null;
        try {
            if (connectionSize.get() < maxActive) {
                //还存在空闲连接
                if (pooledCons.size() != 0) {
                    connection = pooledCons.poll();
                } else {
                    connection = ConnectionFactory.createConnection();
                }
                connectionSize.getAndIncrement();
            } else {
                if (time != 0) {
                    throw new RuntimeException("获取数据库连接失败");
                }
                //等待一段事件再去获取
                condition.await(maxWait, TimeUnit.SECONDS);
                getConnections(time + 1);
            }
        } finally {
            lock.unlock();
        }
        return connection;
    }

    //释放连接
    public static void release(Connection connection){
        lock.lock();
        try {
            if(pooledCons.size() < initialSize){
                pooledCons.push(connection);
            }else{
                connection.close();
            }
            connectionSize.decrementAndGet();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

}
